﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using MacomberMapSystem.Common.Properties;
using System.Drawing.Imaging;
using MacomberMapSystem.Common.Internals;
using System.Reflection;
using System.DirectoryServices;
using MacomberMapSystem.Common.Serialization;
using MacomberMapSystem.Common.User_Interfaces.One_Lines;
using System.Threading;

namespace MacomberMapSystem.Common.User_Interfaces.Database
{
    /// <summary>
    /// This form presents a login interface to start up the system
    /// </summary>
    public partial class frmLogin : Form
    {
        #region Variable declarations
        /// <summary>The collection of login options appropraite to this application</summary>
        private List<MM_Login_Option> LoginOptions = new List<MM_Login_Option>();

        /// <summary>The collection of login processes that need to be completed</summary>
        public Dictionary<String, MM_Login_Process> LoginProcesses = new Dictionary<string, MM_Login_Process>();

        /// <summary>The repository in which user name and domain are stored</summary>
        private MM_Repository Repository;

        /// <summary>Whether to log in with default credentials</summary>
        public bool AutoLogin = false;

        #endregion

        #region Initialization
        /// <summary>
        /// Initialize a new login form
        /// </summary>
        public frmLogin(MM_Repository Repository)
        {
            InitializeComponent();
            this.Repository = Repository;
            this.Text = "Login - [" + Application.ProductName + "]";
            cmbDomain.SelectedIndex = 0;
            pnlDraw.CurrentProcess = null;

            //Pull in our list of domains
            try
            {
                cmbDomain.Items.Clear();
                DirectoryEntry en = new DirectoryEntry("LDAP://");
                DirectorySearcher srch = new DirectorySearcher("objectCategory=Domain");
                using (SearchResultCollection sColl = srch.FindAll())
                    foreach (SearchResult sRes in sColl)
                        cmbDomain.Items.Add(sRes.Properties["name"][0].ToString().ToUpper());
                if (!String.IsNullOrEmpty(Environment.UserDomainName) && !cmbDomain.Items.Contains(Environment.UserDomainName.ToUpper()))
                    cmbDomain.Items.Add(Environment.UserDomainName.ToUpper());
            }
            catch (Exception)
            { }

            if (!string.IsNullOrEmpty(Environment.UserDomainName))
                cmbDomain.Text = Environment.UserDomainName;

            txtUserName.Text = Environment.UserName;
        }

        /// <summary>
        /// Add a new logon option
        /// </summary>
        /// <param name="Caption"></param>
        /// <param name="ToolTip"></param>
        /// <param name="Default"></param>
        /// <param name="RequireSelection"></param>
        /// <param name="LogonCode"></param>
        /// <param name="Choices"></param>
        public void AddLoginOption(String Caption, String ToolTip, String Default, bool RequireSelection, MM_Login_Option.LogonCodeDelegate LogonCode, params string[] Choices)
        {
            LoginOptions.Add(new MM_Login_Option(Caption, ToolTip, tTip, Default, RequireSelection, this, LogonCode, Choices));
        }
        #endregion



        /// <summary>
        /// Handle the OK button click
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOk_Click(object sender, EventArgs e)
        {
            Login();
        }

        /// <summary>
        /// Login to our system
        /// </summary>
        public void Login()
        {
            btnOk.Enabled = false;
            //First, log onto our domain
            if (!MM_System_Interface.ValidateCredentials(txtUserName.Text, txtPassword.Text, cmbDomain.Text))
            {
                pnlDraw.CurrentProcess = new MM_Login_Process("Login", null);
                pnlDraw.CurrentProcess.Err = new InvalidOperationException("Inavlid credentials!");
                return;
            }



            //Update our size and progress bar
            pnlDraw.CurStep = 0;
            pnlDraw.NumSteps = LoginOptions.Count + this.LoginProcesses.Count;

            //Assign our user name and domain
            Repository.UserName = txtUserName.Text;
            Repository.UserDomain = cmbDomain.Text;

            Exception ex;
            foreach (MM_Login_Option LoginOption in LoginOptions)
            {
                pnlDraw.CurrentProcess = new MM_Login_Process(LoginOption.Caption, null);
                pnlDraw.CurStep++;
                if (!LoginOption.LogOn(out ex))
                {
                    pnlDraw.CurrentProcess.Err = ex;
                    MessageBox.Show("Error in step " + LoginOption.Caption + ": " + ex.ToString(), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
            }


            //Now, go through each login process
            foreach (KeyValuePair<String, MM_Login_Process> LoginProcess in this.LoginProcesses)
            {
                pnlDraw.CurrentProcess = LoginProcess.Value;
                pnlDraw.CurStep++;

                //Now, spool our process out                
                IAsyncResult ar = LoginProcess.Value.BeginInvoke(out ex);
                while (!ar.IsCompleted)
                {
                    pnlDraw.Refresh();
                    Application.DoEvents();
                    Thread.Sleep(250);
                }

                bool Result = LoginProcess.Value.EndInvoke(ar, out ex);
                LoginProcess.Value.Err = ex;
                pnlDraw.Refresh();

                if (!Result)
                {
                    pnlDraw.CurrentProcess.Err = ex;
                    MessageBox.Show("Error in " + LoginProcess.Key + ": " + ex.Message + "\n\n" + MM_System_Interface.ConvertError(ex), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
            }

            this.DialogResult = DialogResult.OK;
            pnlDraw.CurrentProcess = null;
            this.Close();
        }


        /// <summary>
        /// Handle our cancel button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Cancel;
            this.Close();
        }

        /// <summary>
        /// Highlight our password field on startup
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void frmLogin_Shown(object sender, EventArgs e)
        {
            txtPassword.Focus();
            this.Focus();
            this.Activate();
            this.ShowInTaskbar = true;
            if (AutoLogin)
            {
                this.Hide();
                this.Height = 88;
                BeginInvoke(new EventHandler(btnOk_Click), btnOk, EventArgs.Empty);
            }
        }

    }
}